import processing.serial.*;

int TOPX = 30;
int TOPY = 30;
int LENX=30*8;
int LENY=30*8;
int WIDTHX=30;
int WIDTHY=30;

int BACKGROUND=51;
int OFFCOLOR=100;
int MAXFRAME=64;
int MINFRAME=0;

int BUTTON_START_X= 310;
int BUTTON_START_Y= 80;
int BUTTON_ROW_HEIGHT= 60;
int BUTTON_WIDTH=24;
int BUTTON_SPACE = 10;

String DATA_FILE = "savedat.csv";

int pX, pY;
color c1,c2;
PFont label;

LedMatrix[] led;
LedMatrix c_led;
LedMatrix buf_led;

PrevButton btn_prev;
NextButton btn_next;

RunButton   btn_run;
StopButton  btn_stop;
ClearButton btn_clear;
EraseButton btn_erase;
SendButton  btn_send;
CopyButton  btn_copy;
PasteButton btn_paste;
SaveButton  btn_save;
LoadButton  btn_load;
InsertButton btn_insert;


boolean c_sw = false;
boolean run_sw = false;


int p_frame=0;    // Current frame Number
int max_frame=0;  // Max frame Numnber

PImage mask;


Serial port;


// ==========================================
//   Setup ( )
// ==========================================
void setup(){
  int i,j;

  background(BACKGROUND);
  size(520,320);


  PImage img_run=loadImage("player_play.png");
  PImage img_stop=loadImage("agt_pause-queue.png");
  PImage img_clear=loadImage("editclear.png");
  PImage img_erase=loadImage("edit_remove.png");
  PImage img_send=loadImage("exec.png");
  PImage img_copy=loadImage("editcopy.png");
  PImage img_paste=loadImage("editpaste.png");
  PImage img_save=loadImage("filesave.png");
  PImage img_load=loadImage("fileopen.png");
  PImage img_insert=loadImage("edit_add.png");

  mask = loadImage("blank.png");



  stroke(255);
  fill(0);
  rect(TOPX,TOPY,LENX,LENY);
  stroke(195);
  for (i=1 ; i < 8 ; i++){
    line(TOPX,TOPY+WIDTHY*i,TOPX+WIDTHX*8,TOPY+WIDTHY*i);
    line(TOPX+WIDTHX*i,TOPY,TOPX+WIDTHX*i,TOPY+WIDTHY*8);
  }

  led= new LedMatrix[MAXFRAME];
  led[0] = new LedMatrix();
  c_led = led[0];
  buf_led = new LedMatrix();

  label = createFont("Arial",14);


  // textFont(label);

  c1 = color(20,20,20);
  btn_prev = new PrevButton (3,75,19,100,"<<");
  btn_next = new NextButton (3+TOPX+LENX,75,19,100,">>");

  i = BUTTON_START_X;
  j = BUTTON_START_Y;  

  btn_run    = new RunButton   (i , j , BUTTON_WIDTH, 20 , img_run, "Run");

  i += BUTTON_WIDTH + BUTTON_SPACE; 
  btn_stop   = new StopButton  (i , j , BUTTON_WIDTH, 20 , img_stop, "Pause");

  i += BUTTON_WIDTH + BUTTON_SPACE; 

  i = BUTTON_START_X;
  j = BUTTON_START_Y + BUTTON_ROW_HEIGHT;  


  btn_copy   = new CopyButton  (i , j , BUTTON_WIDTH, 20 , img_copy, "Copy");
  i += BUTTON_WIDTH + BUTTON_SPACE; 
  btn_paste   = new PasteButton(i , j , BUTTON_WIDTH, 20 , img_paste, "Paste");
  i += BUTTON_WIDTH + BUTTON_SPACE; 
  btn_clear  = new ClearButton (i , j , BUTTON_WIDTH, 20 , img_clear, "Clear");
  i += BUTTON_WIDTH + BUTTON_SPACE; 
  btn_insert  = new InsertButton (i , j , BUTTON_WIDTH, 20 , img_insert, "Add");
  i += BUTTON_WIDTH + BUTTON_SPACE; 
  btn_erase  = new EraseButton (i , j , BUTTON_WIDTH, 20 , img_erase, "Del");

  i = BUTTON_START_X;
  j = BUTTON_START_Y + BUTTON_ROW_HEIGHT + BUTTON_ROW_HEIGHT;  

  btn_load   = new LoadButton  (i , j , BUTTON_WIDTH, 20 , img_load, "Load");
  i += BUTTON_WIDTH + BUTTON_SPACE; 
  btn_save   = new SaveButton  (i , j , BUTTON_WIDTH, 20 , img_save, "Save");
  i += BUTTON_WIDTH + BUTTON_SPACE; 

  i = BUTTON_START_X;
  j = BUTTON_START_Y + BUTTON_ROW_HEIGHT + BUTTON_ROW_HEIGHT + BUTTON_ROW_HEIGHT;  


  btn_send   = new SendButton  (i , j , BUTTON_WIDTH, 20 , img_send, "Upload");
  i += BUTTON_WIDTH + BUTTON_SPACE; 

  println(Serial.list());
  //   port = new Serial(this, Serial.list()[2], 9600); 


}

// ==========================================
//   draw  ( )
// ==========================================
void draw(){
  int dsp_p_frame, dsp_max_frame;
  if (run_sw) {
    frameRate(10);
    p_frame ++ ;
    if ( p_frame > max_frame) { 
      p_frame =0;
    }
    // println ("in run mode, p_frame is " + p_frame);
    c_led = led[p_frame];
  } 
  else {
    frameRate(60);
  }
  noStroke();
  fill(BACKGROUND);
  rect(0,0,250,23);
  fill(255);
  smooth();

  dsp_p_frame = p_frame +1 ;
  dsp_max_frame = max_frame +1 ;

  textFont(label);

  text ("Flame = " + dsp_p_frame + "/" + dsp_max_frame ,160,10);
  drawAll();


}
// ==========================================
//   mousePressed  ( )
// ==========================================
void mousePressed(){
  if (!run_sw) {
    if (mouseX > TOPX  && mouseX < TOPX+LENX && mouseY > TOPY && mouseY < TOPY + LENY){
      pX =floor (map( mouseX-TOPX,0,LENX,0,8));
      pY= floor (map( mouseY-TOPY,0,LENY,0,8));
      // debug
      // println(" Mouse : " + mouseX + " " + mouseY + " Mapped :" + pX + " " +pY);

      // invert off/on
      c_led.setStats(pX, pY, !c_led.getStats(pX, pY));

      if ( c_led.getStats(pX, pY) )  // is ture
      {
        switch_led(pX, pY, true);
      } 
      else {
        switch_led(pX, pY, false);
      }
    } 
    else if ( btn_prev.pressed() ) {
      btn_prev.setButton(100);
      if ( !c_sw) {
        btn_prev.doAction();
      }
    } 
    else if ( btn_next.pressed() ) {
      btn_next.setButton(100);      
      if ( !c_sw) {
        btn_next.doAction();
      }
    } 
    else if ( btn_run.pressed() ) {
      btn_run.setButton(100);
      if ( !c_sw) {
        btn_run.doAction();
      }
    } 
    else if ( btn_clear.pressed() ) {
      btn_clear.setButton(100);
      if ( !c_sw) {
        btn_clear.doAction();
      }
    } 
    else if ( btn_erase.pressed() ) {
      btn_erase.setButton(100);
      if ( !c_sw) {
        btn_erase.doAction();
      }
    } 
    else if ( btn_send.pressed() ) {
      btn_send.setButton(100);
      if ( !c_sw) {
        btn_send.doAction();
      }
    } 
    else if ( btn_copy.pressed() ) {
      btn_copy.setButton(100);
      if ( !c_sw) {
        btn_copy.doAction();
      }
    } 
    else if ( btn_paste.pressed() ) {
      btn_paste.setButton(100);
      if ( !c_sw) {
        btn_paste.doAction();
      }
    } 
    else if ( btn_save.pressed() ) {
      btn_save.setButton(100);
      if ( !c_sw) {
        btn_save.doAction();
      }
    } 
    else if ( btn_insert.pressed() ) {
      btn_insert.setButton(100);
      if ( !c_sw) {
        btn_insert.doAction();
      }
    } 
    else if ( btn_load.pressed() ) {
      btn_load.setButton(100);
      if ( !c_sw) {
        btn_load.doAction();
      }
    }
    c_sw = true ;
  } 
  else {
    if ( btn_stop.pressed() ) {
      btn_stop.setButton(100);
      btn_stop.doAction();
    }
  }

}

// ==========================================
//   mouseReleased  ( )
// ==========================================
void mouseReleased(){
  btn_prev.setButton(0);
  btn_next.setButton(0);
  btn_run.setButton(0);
  btn_stop.setButton(0);
  btn_clear.setButton(0);
  btn_erase.setButton(0);
  btn_send.setButton(0);
  btn_copy.setButton(0);
  btn_paste.setButton(0);
  btn_insert.setButton(0);
  btn_save.setButton(0);
  btn_load.setButton(0);
  c_sw = false ;
}

// ==========================================
//   functions
// ==========================================

//  drawAll
void drawAll() {
  int i,j;
  for (i=0; i<8 ;i++){
    for (j=0; j<8; j++){
      switch_led(i, j, c_led.getStats(i,j));
    }
  }
}

//  switch_led
void switch_led(int pX, int pY, boolean on){
  noStroke();
  if (on) {
    fill(255,0,0);
  } 
  else {
    fill(OFFCOLOR);
  }
  ellipse(TOPX + WIDTHX*pX + WIDTHX/2, TOPY + WIDTHY * pY +WIDTHY/2, 20,20);
}




// ------------------------------------------------------
//  L e d M a t r ix
// ------------------------------------------------------
class LedMatrix {
  boolean[][] stats = new boolean[8][8];

  // Constructor
  LedMatrix(){
    init();
  }
  // init 
  void init(){
    int i,j;
    for (i=0 ; i < 8 ; i++){
      for (j=0 ; j < 8 ; j++){
        stats[i][j]=false;
      }
    }
  }

  // getStats()
  boolean getStats(int x, int y){
    return stats[x][y];
  }
  // setStats()
  void setStats(int x, int y, boolean val){
    stats[x][y] = val;
  }

  // on()  for future use
  void on(int x, int y){
    stats[x][y] = true;
  }

  // off() for future use
  void off(int x, int y){
    stats[x][y] = false;
  }

  // getString() for DEBUG
  String getStrings(){
    int x,y;
    String buf = "";

    for (y=0 ; y<8 ; y++){
      String r="";
      for (x=0 ; x < 8 ; x++){
        r = r + ( getStats(x,y) ? "1" : "0" );
      }
      buf = buf + unbinary(r) + ",";
    }
    return buf;
  }

  // getDump()
  Byte[] getDump(){
    int x,y;
    String r;
    Byte[] b= new Byte[8];

    for (y=0 ; y<8 ; y++){
      r="";
      for (x=0 ; x < 8 ; x++){
        r = r + ( getStats(x,y) ? "1" : "0" );
      }
      println(r); // DEBUG
      b[y]= byte(unbinary(r));
    }
    return b;
  }
}


// ------------------------------------------------------
//  B u t t o n
// ------------------------------------------------------
class Button  {
  int _x,_y,_w,_h;

  Button (int x, int y, int width, int height) {
    _x = x;
    _y = y;
    _w = width;
    _h = height;
  }

  boolean pressed () {
    if (mouseX > _x && mouseX < _x + _w && mouseY > _y && mouseY < _y + _h ){
      return true;
    } 
    else {
      return false;
    }
  }
}
// ------------------------------------------------------
//  F r a m eB u t t o n
// ------------------------------------------------------

class FrameButton extends Button {
  String _msg;
  color _c;

  FrameButton (int x, int y, int width, int height,String msg ) {
    super(x, y, width, height);
    _msg = msg;
    setButton(0);

  }

  void setButton (int c) {
    stroke(255);
    fill(c);
    rect(_x,_y,_w,_h);   
    fill(255);
    textAlign(CENTER,CENTER);
    textFont(label);
    text (_msg, _x + _w/2, _y + _h/2);

  }

  void doAction(int x){
    int p; 
    p = p_frame + x;

    if ( p < MINFRAME ) {
      p = MINFRAME;
    }
    if (p > MAXFRAME) {
      p = MAXFRAME;
    }

    if ( led[p] == null ) {
      led[p] = new LedMatrix();
    }
    p_frame = p ;
    if (p_frame > max_frame) { 
      max_frame = p_frame; 
    } 
    c_led = led[p];

    fill(255);
    text ("Flame:" + p_frame + " ",125,10);
  }

}

// ------------------------------------------------------
//  N e x t B u t t o n
// ------------------------------------------------------

class NextButton extends FrameButton {

  NextButton (int x, int y, int width, int height,String msg ) {
    super (x, y, width, height, msg );
  }

  void doAction() {
    super.doAction(1);
  }
}

// ------------------------------------------------------
//  P r e v B u t t o n
// ------------------------------------------------------

class PrevButton extends FrameButton {
  PrevButton (int x, int y, int width, int height,String msg ) {
    super (x, y, width, height, msg );
  }
  void doAction() {
    super.doAction(-1);
  }
}

// ------------------------------------------------------
//  C o n t r o l B u t t o n
// ------------------------------------------------------
class ControlButton extends Button {

  PImage _img;
  String _msg;
  PFont label_button;


  ControlButton (int x, int y, int width, int height, PImage img,String msg) {
    /*
      _x = x;
     _y = y;
     _w = width;
     _h = height;
     */
    super(x, y, width, height);
    _img = img;
    _msg = msg;
    setButton(0);
    fill(255);
    /*
    label_button = createFont("Arial",10);
    textFont(label_button);
    text(msg, _x+13, _y+39);
    */

  }
  void setButton (int c) {
    int diff=0;

    image(mask,_x,_y);

    if ( c > 0 ) { // button pressed
      diff = 2;
      stroke(0);
      strokeWeight(1);
      line(_x-2, _y-1, _x-2, _y-1 + 30);
      line(_x-2, _y-1, _x-2 + 28 , _y-1);
      stroke(255);
      strokeWeight(2);
      line(_x-2 +28 , _y-1, _x-2 + 28 , _y-1 + 30);
      strokeWeight(3);
      line(_x-2 +28 , _y-1 + 30, _x-2+1  , _y-1 + 30);

    } 
    else {
      stroke(255);
      strokeWeight(1);
      line(_x-2, _y-1, _x-2, _y-1 + 30);
      line(_x-2, _y-1, _x-2 + 28 , _y-1);
      stroke(0);
      strokeWeight(2);
      line(_x-2 +28 , _y-1, _x-2 + 28 , _y-1 + 30);
      strokeWeight(3);
      line(_x-2 +28 , _y-1 + 30, _x-2+1  , _y-1 + 30);

    }
    // fill(BACKGROUND);
    // rect(_x-2, _y-1, 28,30);
    strokeWeight(1);

    smooth();
    stroke(255);
    label_button = createFont("Arial",10);
    textFont(label_button);
    text(_msg, _x+13, _y+39);
    // println(_img);
    image(_img, _x + diff, _y + diff);
  }


}

// ------------------------------------------------------
//  R u n B u t t o n
// ------------------------------------------------------
class RunButton extends ControlButton {
  RunButton (int x, int y, int width, int height,PImage img, String msg ) {
    super (x, y, width, height, img, msg );
  }
  void doAction() {
    if (max_frame > 0 ) {
      run_sw = true;
      p_frame = 0;
      c_led = led[0];
    }
  }
}

// ------------------------------------------------------
//  S t o p B u t t o n
// ------------------------------------------------------
class StopButton extends ControlButton {
  StopButton (int x, int y, int width, int height,PImage img, String msg ) {
    super (x, y, width, height, img, msg );
  }
  void doAction() {
    run_sw = false ;
  }
}

// ------------------------------------------------------
//  C l e a r B u t t o n
// ------------------------------------------------------
class ClearButton extends ControlButton {
  ClearButton (int x, int y, int width, int height,PImage img, String msg ) {
    super (x, y, width, height, img, msg );
  }
  void doAction() {
    c_led.init();
  }
}

// ------------------------------------------------------
//  E r a s e B u t t o n
// ------------------------------------------------------
class EraseButton extends ControlButton {
  EraseButton (int x, int y, int width, int height,PImage img, String msg ) {
    super (x, y, width, height, img, msg );
  }
  void doAction() {
    int i;

    // can not erase last frame
    if ( max_frame == 0 ) {
      return;
    }

    led[p_frame] = null;
    if (p_frame == max_frame){
      p_frame--;
    } 
    else {
      for ( i=p_frame;  i<max_frame; i++) {
        led[i]=led[i+1];
      }
      led[max_frame]=null;
    }
    max_frame--;
    c_led=led[p_frame];


  }
}
// ------------------------------------------------------
//  I n s e r t B u t t o n
// ------------------------------------------------------
class InsertButton extends ControlButton {
  InsertButton (int x, int y, int width, int height,PImage img, String msg ) {
    super (x, y, width, height, img, msg );
  }
  void doAction() {
    int p;

    // no more frame
    if ( max_frame == MAXFRAME ) {
      return;
    }

    for ( p = max_frame ; p >= p_frame ; p--) {
      led[p+1] = led[p];
    }
    led[p_frame] = new LedMatrix();
    max_frame++;
    c_led = led[p_frame];



    // 1,2,*3*,4,5,6     6 to 7, 5 to 6 , 4 to 5, 3 to 4 , 3 new)


  }
}

// ------------------------------------------------------
//  C o p y B u t t o n
// ------------------------------------------------------
class CopyButton extends ControlButton {
  CopyButton (int x, int y, int width, int height,PImage img, String msg ) {
    super (x, y, width, height, img, msg );
  }
  void doAction() {
    int i,j;
    for (i=0 ; i < 8 ; i++){
      for (j=0 ; j < 8 ; j++){
        buf_led.setStats(i,j,c_led.getStats(i,j));
      }
    }
  }
}

// ------------------------------------------------------
//  P a s t e B u t t o n
// ------------------------------------------------------
class PasteButton extends ControlButton {
  PasteButton (int x, int y, int width, int height,PImage img, String msg ) {
    super (x, y, width, height, img, msg );
  }
  void doAction() {
    int i,j;
    for (i=0 ; i < 8 ; i++){
      for (j=0 ; j < 8 ; j++){
        c_led.setStats(i,j,buf_led.getStats(i,j));
      }
    }

  }
}

// ------------------------------------------------------
//  S a v e B u t t o n
// ------------------------------------------------------
class SaveButton extends ControlButton {
  SaveButton (int x, int y, int width, int height,PImage img, String msg ) {
    super (x, y, width, height, img, msg );
  }
  void doAction() {
    int p;
    String s;
    String [] buf={
    };

    for (p = 0 ; p <= max_frame ; p++){
      s = p + "," + max_frame + "," + led[p].getStrings();
      buf = append (buf,s);
    }
    saveStrings("data/"+ DATA_FILE,buf);

  }
}

// ------------------------------------------------------
//  L o a d B u t t o n
// ------------------------------------------------------
class LoadButton extends ControlButton {
  LoadButton (int x, int y, int width, int height,PImage img, String msg ) {
    super (x, y, width, height, img, msg );
  }
  void doAction() {
    String lines[] = loadStrings(DATA_FILE);

    led = null ; 
    led = new LedMatrix[MAXFRAME];

    for (int i = 0 ; i <lines.length ; i++) {
      String p[] = splitTokens(lines[i], ",");
      led[i] = new LedMatrix();
      println ("i=" + i );          // DEBUG
      println (lines[i]);           // DEBUG
      for (int j=2 ; j <=9 ; j++){
        int pj = int(p[j]);   // ex. 0-255
        println ("  j =" + j );     // DEBUG
        println ("  pj =" + pj );   // DEBUG
        for (int k=0 ; k < 8 ; k++){
          if ( ( pj >>(7-k) & 1 ) == 1) {
            led[i].on(k,j-2);
          }
        }
      }
    }

    max_frame=lines.length-1;
    p_frame=0;
    c_led = led[p_frame];
  }
}

// ------------------------------------------------------
//  S e n d B u t t o n
// ------------------------------------------------------
class SendButton extends ControlButton {
  SendButton (int x, int y, int width, int height,PImage img, String msg ) {
    super (x, y, width, height, img, msg );
  }
  void doAction() {
    int p;
    Byte[] b = new Byte[8];

    port.write(max_frame);    

    for (p = 0 ; p <=   max_frame ; p++){
      b = led[p].getDump();
      for (int i=0 ; i< 8 ; i++){
        port.write(b[i]);
      }
    }
  }
}








